<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>简易图片处理工具</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                    },
                }
            }
        }
    </script>
</head>
<body class="bg-gray-50 min-h-screen">
    <div class="container mx-auto px-4 py-12 max-w-3xl">
        <!-- 标题区域 -->
        <header class="text-center mb-8">
            <h1 class="text-2xl md:text-3xl font-bold text-gray-800 mb-3">
                <i class="fa fa-picture-o text-primary mr-2"></i>简易图片处理工具
            </h1>
            <p class="text-gray-600">
                上传图片后自动处理为 260×320 像素，大小不超过 60KB，并自动下载
            </p>
        </header>

        <main class="bg-white rounded-xl shadow-lg p-6 md:p-8">
            <!-- 上传区域 -->
            <div id="dropArea" class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center cursor-pointer hover:border-primary transition-all duration-300">
                <i class="fa fa-cloud-upload text-5xl text-gray-400 mb-4"></i>
                <p class="text-gray-600 mb-2">拖放图片到此处，或点击上传</p>
                <p class="text-gray-400 text-sm">支持 JPG、PNG 格式</p>
                <input type="file" id="fileInput" accept="image/jpeg, image/png" class="hidden">
            </div>

            <!-- 状态区域 -->
            <div id="statusArea" class="mt-6 text-center hidden">
                <div id="loadingIndicator" class="hidden">
                    <div class="inline-block animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-primary mb-2"></div>
                    <p class="text-gray-600">正在处理图片...</p>
                </div>
                <div id="errorMessage" class="text-red-500 hidden">
                    <i class="fa fa-exclamation-circle text-xl mb-2"></i>
                    <p>处理图片时出错，请重试</p>
                </div>
            </div>

            <!-- 预览区域 -->
            <div id="previewArea" class="mt-6 hidden">
                <h3 class="text-lg font-medium mb-3 text-gray-700">处理结果预览</h3>
                <div class="grid grid-cols-2 gap-4">
                    <div>
                        <p class="text-sm text-gray-500 mb-1">原始图片</p>
                        <img id="originalImage" class="max-w-full max-h-[150px] object-contain" alt="原始图片">
                    </div>
                    <div>
                        <p class="text-sm text-gray-500 mb-1">处理后图片</p>
                        <img id="processedImage" class="max-w-full max-h-[150px] object-contain" alt="处理后图片">
                    </div>
                </div>
            </div>
        </main>

        <footer class="mt-8 text-center text-gray-500 text-sm">
            <p>所有处理均在本地完成，不会上传您的图片</p>
        </footer>
    </div>

    <script>
        // 配置参数
        const DEFAULT_WIDTH = 260;
        const DEFAULT_HEIGHT = 320;
        const DEFAULT_SIZE_KB = 60;
        
        // 获取DOM元素
        const dropArea = document.getElementById('dropArea');
        const fileInput = document.getElementById('fileInput');
        const statusArea = document.getElementById('statusArea');
        const loadingIndicator = document.getElementById('loadingIndicator');
        const errorMessage = document.getElementById('errorMessage');
        const previewArea = document.getElementById('previewArea');
        const originalImage = document.getElementById('originalImage');
        const processedImage = document.getElementById('processedImage');
        
        // 拖放事件处理
        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            dropArea.addEventListener(eventName, preventDefaults, false);
        });
        
        function preventDefaults(e) {
            e.preventDefault();
            e.stopPropagation();
        }
        
        ['dragenter', 'dragover'].forEach(eventName => {
            dropArea.addEventListener(eventName, highlight, false);
        });
        
        ['dragleave', 'drop'].forEach(eventName => {
            dropArea.addEventListener(eventName, unhighlight, false);
        });
        
        function highlight() {
            dropArea.classList.add('border-primary', 'bg-blue-50');
        }
        
        function unhighlight() {
            dropArea.classList.remove('border-primary', 'bg-blue-50');
        }
        
        dropArea.addEventListener('drop', handleDrop, false);
        
        function handleDrop(e) {
            const dt = e.dataTransfer;
            const file = dt.files[0];
            handleFiles(file);
        }
        
        // 点击上传
        dropArea.addEventListener('click', () => {
            fileInput.value = '';
            fileInput.click();
        });
        
        fileInput.addEventListener('change', () => {
            if (fileInput.files.length > 0) {
                handleFiles(fileInput.files[0]);
            }
        });
        
        // 处理上传的文件
        function handleFiles(file) {
            if (!file.type.match('image/jpeg|image/png')) {
                alert('请上传JPG或PNG格式的图片');
                return;
            }
            
            // 显示处理状态
            showLoading();
            
            // 读取图片
            const reader = new FileReader();
            reader.onload = function(e) {
                const img = new Image();
                img.onload = function() {
                    // 显示原始图片预览
                    originalImage.src = e.target.result;
                    
                    // 处理图片
                    processImage(img);
                };
                img.src = e.target.result;
            };
            reader.readAsDataURL(file);
        }
        
        // 处理图片
        function processImage(img) {
            try {
                // 调整分辨率（缩放和裁剪）
                const resizedCanvas = resizeAndCropImage(img, DEFAULT_WIDTH, DEFAULT_HEIGHT);
                
                // 压缩到指定大小
                compressToTargetSize(resizedCanvas, DEFAULT_SIZE_KB, (dataUrl, info) => {
                    // 显示处理后图片预览
                    processedImage.src = dataUrl;
                    previewArea.classList.remove('hidden');
                    
                    // 自动下载图片
                    downloadImage(dataUrl);
                    
                    // 隐藏加载状态
                    hideStatus();
                });
            } catch (error) {
                console.error('图片处理错误:', error);
                showError();
            }
        }
        
        // 调整分辨率：先按比例缩放，再裁剪
        function resizeAndCropImage(img, targetW, targetH) {
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            
            // 计算原始宽高比和目标宽高比
            const originalRatio = img.naturalWidth / img.naturalHeight;
            const targetRatio = targetW / targetH;
            
            let scaledW, scaledH;
            
            // 根据比例决定缩放方式
            if (originalRatio > targetRatio) {
                // 原始图片更宽，按高度缩放，然后裁剪宽度
                scaledH = targetH;
                scaledW = img.naturalWidth * (targetH / img.naturalHeight);
            } else {
                // 原始图片更高，按宽度缩放，然后裁剪高度
                scaledW = targetW;
                scaledH = img.naturalHeight * (targetW / img.naturalWidth);
            }
            
            // 设置canvas尺寸为目标尺寸
            canvas.width = targetW;
            canvas.height = targetH;
            
            // 计算裁剪位置
            const offsetX = (scaledW > targetW) ? (scaledW - targetW) / 2 : 0;
            const offsetY = (scaledH > targetH) ? (scaledH - targetH) / 2 : 0;
            
            // 绘制并裁剪图片
            ctx.drawImage(
                img,
                0, 0, img.naturalWidth, img.naturalHeight,
                -offsetX, -offsetY, scaledW, scaledH
            );
            
            return canvas;
        }
        
        // 压缩图片到目标大小
        function compressToTargetSize(canvas, targetSizeKB, callback) {
            // 目标大小转换为字节
            const targetSizeBytes = targetSizeKB * 1024;
            
            // 二分法查找最佳质量
            let minQuality = 0.1;
            let maxQuality = 1.0;
            let bestQuality = 0.8;
            let bestDataUrl = null;
            let bestInfo = null;
            let iterations = 0;
            const maxIterations = 15;
            
            function testQuality(quality) {
                iterations++;
                
                // 将canvas转换为jpeg
                const dataUrl = canvas.toDataURL('image/jpeg', quality);
                
                // 计算数据URL的大小
                const sizeBytes = Math.round((dataUrl.length * 3) / 4);
                const sizeKB = sizeBytes / 1024;
                
                // 存储当前信息
                const info = {
                    width: canvas.width,
                    height: canvas.height,
                    sizeKB: sizeKB,
                    quality: quality * 100
                };
                
                // 如果找到合适的质量或达到最大迭代次数，返回结果
                if (sizeBytes <= targetSizeBytes || iterations >= maxIterations) {
                    if (!bestDataUrl || sizeBytes > bestInfo.sizeKB * 1024) {
                        bestDataUrl = dataUrl;
                        bestInfo = info;
                    }
                    callback(bestDataUrl, bestInfo);
                    return;
                }
                
                // 调整质量继续尝试
                if (sizeBytes > targetSizeBytes) {
                    maxQuality = quality;
                    if (!bestDataUrl || quality > bestInfo.quality / 100) {
                        bestDataUrl = dataUrl;
                        bestInfo = info;
                    }
                    testQuality((minQuality + maxQuality) / 2);
                } else {
                    minQuality = quality;
                    bestDataUrl = dataUrl;
                    bestInfo = info;
                    testQuality((minQuality + maxQuality) / 2);
                }
            }
            
            // 开始测试
            testQuality(bestQuality);
        }
        
        // 下载图片
        function downloadImage(dataUrl) {
            const link = document.createElement('a');
            link.download = 'processed-image.jpg';
            link.href = dataUrl;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }
        
        // 状态显示函数
        function showLoading() {
            statusArea.classList.remove('hidden');
            loadingIndicator.classList.remove('hidden');
            errorMessage.classList.add('hidden');
            previewArea.classList.add('hidden');
        }
        
        function showError() {
            loadingIndicator.classList.add('hidden');
            errorMessage.classList.remove('hidden');
        }
        
        function hideStatus() {
            statusArea.classList.add('hidden');
            loadingIndicator.classList.add('hidden');
            errorMessage.classList.add('hidden');
        }
    </script>
</body>
</html>
